#include "lualexer.h"
#include <Qsci/qsciscintilla.h>
#include "../lua_parser/luastyle.h"
#include "settingsmanager.h"

LuaLexer::LuaLexer(QObject *parent)
{
    m_parser = NULL;
    for(int i = ETokenUnprocessed; i < ETokenTypeLast; i++)
        m_styles[(StyleTypeEnum)i] = NULL;
    //TODO settings
/*    m_styles[EStyleComment] = new LuaStyle(QColor(0x80, 0x80, 0x80, 255), QColor("white"), true, false);
    m_styles[EStyleString] =  new LuaStyle(QColor(0x0, 0x80, 0x0, 255), QColor("white"), false, true);
    m_styles[EStyleKeyword] = new LuaStyle(QColor(0x0, 0x0, 0x80, 255), QColor("white"), false, true);
    m_styles[EStyleNumber] = new LuaStyle(QColor(0x0, 0x0, 0x80, 255), QColor("white"), false, false);
    //m_styles[EStyleLocal] = new LuaStyle(QColor(0x0, 0x80, 0x80, 255), QColor("white"), false, false);
    m_styles[EStyleLocal] = new LuaStyle(QColor(0x0, 0x0, 0x0, 255), QColor("white"), false, false);
    //m_styles[EStyleParam] = new LuaStyle(QColor(0x0, 0x80, 0x80, 255), QColor("white"), false, true);
    m_styles[EStyleParam] = new LuaStyle(QColor(0x0, 0x00, 0x00, 255), QColor("white"), true, false);
    m_styles[EStyleError] = new LuaStyle(QColor(0xFF, 0x00, 0x00, 255), QColor("white"), false, true);
    //m_styles[EStyleGlobal] = new LuaStyle(QColor(0xFF, 0x00, 0xFF, 255), QColor("white"), false, true);
    m_styles[EStyleGlobal] = new LuaStyle(QColor(0x00, 0x00, 0x00, 255), QColor("white"), false, true);
    m_styles[EStyleStandard] = new LuaStyle(QColor(0x00, 0x00, 0xFF, 255), QColor("white"), false, true);*/

    refreshStyles();

    m_completeOverdraw = false;
    m_hyperLinkStart = -1;
}



LuaLexer::~LuaLexer()
{
    //delete styles
    QHashIterator<StyleTypeEnum, LuaStyle *> i(m_styles);
    while (i.hasNext())
    {
         i.next();
         delete i.value();
     }
}

LuaLexer::LuaLexer(const LuaLexer & aLexer)
    :QsciLexerCustom()
{
    m_parser = aLexer.getParser();
}

LuaLexer & LuaLexer::operator=(const LuaLexer & aLexer)
{
    if(this == &aLexer)
        return *this;

    m_parser = aLexer.getParser();
    return *this;
}

StyleTypeEnum tokenStyle2LexerStyle(TokenTypeEnum aType)
{
    if(aType >= ETokenAnd && aType <= ETokenWhile)
        return EStyleKeyword;
    else if(aType == ETokenString)
        return EStyleString;
    else if(aType == ETokenComment)
        return EStyleComment;
    else if(aType == ETokenNumber)
        return EStyleNumber;
    else if(aType == ETokenLocalIdentifier)
        return EStyleLocal;
    else if(aType == ETokenGlobalIdentifier)
        return EStyleGlobal;
    else if(aType == ETokenParameter)
        return EStyleParam;
    else if(aType == ETokenStandardFunction || aType == ETokenStandardMethod)
        return EStyleStandard;
    else if(aType == ETokenError || aType == ETokenUnfinishedString
            || aType == ETokenMismatchedEnd || aType == ETokenUnrecognizedGlobal)
        return EStyleError;
    else if(aType == ETokenGlobalMethod)
        return EStyleDefault;
    return EStyleDefault;
}


const char *LuaLexer::language() const
{
    return "Lua";
}

QColor LuaLexer::defaultColor(int aStyle) const
{
    StyleTypeEnum tokenType = (StyleTypeEnum)aStyle;
    LuaStyle * style = NULL;
    if(m_styles.contains(tokenType))
        style = m_styles[tokenType];

    if(style)
        return style->getForeground();
    return QsciLexer::defaultColor(aStyle);
}

QFont LuaLexer::defaultFont(int aStyle) const
{
    StyleTypeEnum tokenType = (StyleTypeEnum)aStyle;
    LuaStyle * style = NULL;
    if(m_styles.contains(tokenType))
        style = m_styles[tokenType];
    if(style)
    {
        QFont font = style->getFont();
        font.setStyleStrategy(QFont::PreferAntialias);
        if(aStyle == EStyleHyperlink)
            font.setUnderline(true);
        return font;
    }
    //default
    QFont font("Monospace", 12, QFont::Normal, false);
    font.setStyleStrategy(QFont::PreferAntialias);
    return font;
}

QColor LuaLexer::defaultPaper(int aStyle) const
{
    StyleTypeEnum tokenType = (StyleTypeEnum)aStyle;
    LuaStyle * style = NULL;
    if(m_styles.contains(tokenType))
        style = m_styles[tokenType];

    if(style)
        return style->getBackground();
    return QsciLexer::defaultPaper(aStyle);
}

void LuaLexer::styleText(int aStart, int aEnd)
{
    if(!m_parser)
        return;
    //printf("Styling: %d - %d\n", aStart, aEnd);
    QVector<LuaToken *> tokens = m_parser->getTokens();
    //m_parser->mergeSimilarTokens(tokens);
    size_t count = tokens.size();
    int start  = 0;
    int length = 0;    
    LuaToken * found = NULL;
    int foundIndex = -1;
    for(size_t i = 0; i < count; i++)
    {
        LuaToken * token = tokens[i];
        start = token->getStart();
        length = token->getLength();
        if(start <= aStart && start + length > aStart)
        {
            found = token;
            foundIndex = i;
            break;
        }
    }

    if(!found)
        return;
    int marker = aStart;
    while(marker < aEnd)
    {
        //determine range to style
        //it starts with marker and ends with either aEnd or token's end
        int rangeLength = aEnd - marker;
        if(found->getStart() + found->getLength() < aEnd)
            rangeLength =  found->getLength();
        startStyling(marker);
        setStyling(rangeLength, tokenStyle2LexerStyle(found->getType()));
        //printf("incr styling: %d - %d\n", marker, marker + rangeLength);
        marker += rangeLength;
        if(marker >= found->getStart() + found->getLength())
        {
            foundIndex++;
            found = tokens[foundIndex];
        }
        startStyling(marker);
    }



    if(m_hyperLinkStart > 0 && m_hyperLinkStart >= aStart && m_hyperLinkStart < aEnd)
    {
        /*startStyling(m_hyperLinkStart);
        setStyling(m_hyperLinkLength, EStyleHyperlink);
        startStyling(m_hyperLinkStart + m_hyperLinkLength);*/
        //process hyperlinking now
        int length = aEnd - m_hyperLinkStart;
        if(m_hyperLinkLength + m_hyperLinkStart < aEnd)
            length = m_hyperLinkLength;
        startStyling(m_hyperLinkStart);
        setStyling(length, EStyleHyperlink);
        startStyling(length + m_hyperLinkStart);
    }

}

QString LuaLexer::description(int aStyle) const
{
    return "Default";
}

TokenParser *LuaLexer::getParser()const
{
    return m_parser;
}

void LuaLexer::setParser(TokenParser *aParser)
{
    m_parser = aParser;
}

int LuaLexer::styleBitsNeeded() const
{
    return 5;
}

void LuaLexer::highlightLink(int aStart, int aLength)
{
    startStyling(aStart);
    setStyling(aLength, EStyleHyperlink);
    startStyling(aStart + aLength);
}

void LuaLexer::setCompleteOverdraw(bool aOverdraw)
{
    m_completeOverdraw = aOverdraw;
}

void LuaLexer::setHyperlinkRange(int aStart, int aLength)
{
    m_hyperLinkStart = aStart;
    m_hyperLinkLength = aLength;
}

void LuaLexer::refreshStyles()
{
    //delete styles
    QHashIterator<StyleTypeEnum, LuaStyle *> i(m_styles);
    while (i.hasNext())
    {
         i.next();
         delete i.value();
    }
    //init styles from settings
    SettingsManager * manager = SettingsManager::Instance();
    m_styles[EStyleDefault] = new LuaStyle(
                manager->getSetting("color.foreground.default").getColorValue(),
                manager->getSetting("color.background.default").getColorValue(),
                manager->getSetting("font.default").getFontValue());
    m_styles[EStyleComment] = new LuaStyle(
                manager->getSetting("color.foreground.comment").getColorValue(),
                manager->getSetting("color.background.comment").getColorValue(),
                manager->getSetting("font.comment").getFontValue());
    m_styles[EStyleString] =  new LuaStyle(
                manager->getSetting("color.foreground.string").getColorValue(),
                manager->getSetting("color.background.string").getColorValue(),
                manager->getSetting("font.string").getFontValue());
    m_styles[EStyleKeyword] = new LuaStyle(
                manager->getSetting("color.foreground.keyword").getColorValue(),
                manager->getSetting("color.background.keyword").getColorValue(),
                manager->getSetting("font.keyword").getFontValue());
    m_styles[EStyleNumber] = new LuaStyle(
                manager->getSetting("color.foreground.number").getColorValue(),
                manager->getSetting("color.background.number").getColorValue(),
                manager->getSetting("font.number").getFontValue());
    //m_styles[EStyleLocal] = new LuaStyle(QColor(0x0, 0x80, 0x80, 255), QColor("white"), false, false);
    m_styles[EStyleLocal] = new LuaStyle(
                manager->getSetting("color.foreground.local").getColorValue(),
                manager->getSetting("color.background.local").getColorValue(),
                manager->getSetting("font.local").getFontValue());
    //m_styles[EStyleParam] = new LuaStyle(QColor(0x0, 0x80, 0x80, 255), QColor("white"), false, true);
    m_styles[EStyleParam] = new LuaStyle(
                manager->getSetting("color.foreground.param").getColorValue(),
                manager->getSetting("color.background.param").getColorValue(),
                manager->getSetting("font.param").getFontValue());
    m_styles[EStyleError] = new LuaStyle(
                manager->getSetting("color.foreground.error").getColorValue(),
                manager->getSetting("color.background.error").getColorValue(),
                manager->getSetting("font.error").getFontValue());
    //m_styles[EStyleGlobal] = new LuaStyle(QColor(0xFF, 0x00, 0xFF, 255), QColor("white"), false, true);
    m_styles[EStyleGlobal] = new LuaStyle(
                manager->getSetting("color.foreground.global").getColorValue(),
                manager->getSetting("color.background.global").getColorValue(),
                manager->getSetting("font.global").getFontValue());
    m_styles[EStyleStandard] = new LuaStyle(
                manager->getSetting("color.foreground.standard").getColorValue(),
                manager->getSetting("color.background.standard").getColorValue(),
                manager->getSetting("font.standard").getFontValue());

    QFont italic("Monospace", 8, QFont::Normal, true);
    QFont normal("Monospace", 12, QFont::Normal, false);

    m_styles[EStyleHyperlink] = new LuaStyle(QColor(0x00, 0x00, 0xFF, 255), QColor("white"), normal);
    m_styles[EStyleErrorAnnotation] = new LuaStyle(QColor(0xFF, 0xFF, 0xFF, 255), QColor("red"), italic);
}

